home *** CD-ROM | disk | FTP | other *** search
/ Merciful 1 / Merciful - Disc 1.iso / software / f / friday_night_pool / fridaynightpool.dms / fridaynightpool.adf / source / func.c < prev    next >
C/C++ Source or Header  |  1978-02-25  |  39KB  |  1,532 lines

  1. #include <exec/types.h>
  2. #include <exec/memory.h>
  3. #include <graphics/view.h>
  4. #include <intuition/intuition.h>
  5. #include <graphics/gfxmacros.h>
  6. #include <proto/exec.h>
  7. #include <proto/graphics.h>
  8. #include <proto/intuition.h>
  9. #include <dos.h>
  10. #include <proto/dos.h>
  11. #include <math.h>
  12. #include <exec/devices.h>
  13. #include <devices/audio.h>
  14. #include <hardware/custom.h>
  15.  
  16. #define CUE 0
  17. #define BLK 5
  18.  
  19. #define BASE 200 /* V.important constant. Used in ALL physical calcs. */
  20. #define BASESP 1000
  21. #define BASEII 4 /* For root calcs which need plenty of precision */
  22.  
  23. #define TABLELENGTH (272 * BASE) /* 272 is actual length in pixels */
  24. #define TABLEWIDTH ((TABLELENGTH * 5 / 8)-BASE)
  25.  
  26. #define X1CORNER 24
  27. #define Y1CORNER 62
  28. #define X2CORNER (X1CORNER + TABLELENGTH / BASE)
  29. #define Y2CORNER (Y1CORNER + TABLEWIDTH / BASE)
  30.  
  31. #define BALLRADIUS (7 * BASE) /* 7 pixels */
  32. #define BALLDIAMETER (BALLRADIUS * 2)
  33. #define SCRNBALLDIAMETER (BALLDIAMETER / BASE)
  34. #define SEMICIRCRAD (TABLEWIDTH/6)
  35. #define PLACEPACK (TABLELENGTH * 5 / 8)
  36. #define PACKHORIZSEP (BALLDIAMETER - 2*BASE)
  37. #define POCKET (BALLRADIUS + 5*BASE)
  38. #define SCRNPOCKET (POCKET / BASE)
  39. #define CUETIP 10
  40. #define MAXCUELENGTH 80
  41.  
  42. #define CLOCKWISE 1
  43. #define ANTICLOCKWISE 2
  44. #define SMALL 1
  45. #define LARGE 2
  46. #define UP 1
  47. #define DOWN 2
  48. #define NOHIT -1
  49. #define ON TRUE
  50. #define OFF FALSE
  51. #define HIT 3
  52. #define UPDATE 3
  53. #define ICON 2
  54. #define VIEW 1
  55. #define NOREFRESH 2
  56.  
  57. #define RACKED    1
  58. #define BROKEN    0
  59. #define OPEN    2
  60. #define SPREAD 3
  61.  
  62. #undef SINGLE
  63.  
  64. enum icons { PLYR1,PLYR2,PRACTICE,DEMO,PLAY,QUIT,_BAIZE,_BALL1,_BALL2,
  65. SINGLE,BEST3,BEST5,UNLIMITED,STRIP,BALL10,BALL16,
  66. OPPONENTBASE,ICON17,ICON18,ICON19,STRIPPERBASE };
  67.  
  68. enum args { GAMETYPE,GAMELENGTH,BAIZE,BALL1,BALL2,BALLCOUNT,OPPONENT,STRIPPER };
  69.  
  70. #define HUMANPLYR 0
  71. #define COMPLYR   1
  72.  
  73. #define FRICTION (BASESP / 300)
  74. #define SPINFRICTION 3
  75. #define SPEEDINC (BASESP / 16)
  76. #define MAXSPEED (BASESP * 4)
  77. #define MINSPEED (BASESP / 4)
  78.  
  79. #define ESC 69
  80. #define RETURN 68
  81. #define SPACE 64
  82. #define LCSR 79
  83. #define RCSR 78
  84. #define UCSR 76
  85. #define DCSR 77
  86. #define F1 80
  87. #define F2 81
  88. #define F3 82
  89. #define F4 83
  90. #define F6 85
  91. #define F10 89
  92.  
  93. #define FLASH 2
  94.  
  95. #define JOYFIRE 0xbfe001
  96. #define LMOUSE 1
  97. #define RMOUSE 2
  98.  
  99. #define MEMSIZE 7000
  100.  
  101. void DoControl(void);
  102. void DrawCue(short);
  103. void ChangePower();
  104. short ChangeSpin(void);
  105. void DrawCross(short);
  106. void MoveCue(short,short);
  107. void DoAssigns(void);
  108. void SetUpTable(void);
  109. void DoOptions(void);
  110. short GetInput(void);
  111. char UpdateBallPos(void);
  112. void WaitBeam(short);
  113. short CheckPotted(short);
  114. void CheckBounce(short);
  115. void CheckCollision(void);
  116. void MakeCollision(short,short);
  117. void DrawBall(short,short);
  118. void DrawBallDirect(short,short,short);
  119. short FindAngle(WORD,WORD,WORD);
  120. void SuperImpose(struct RastPort *,short,short,struct RastPort *,
  121.     short,short,short,short,short,short);
  122. void WriteMessage(short,short,short,short);
  123. void ScrubMessage(void);
  124. void PlayShot(void);
  125. void CheckResult(void);
  126. void CheckWhitePotted(void);
  127. short TouchingBall(short);
  128. void PlayComputerShot(void);
  129. void CopyBalls(struct ballstruct*,struct ballstruct*);
  130. void CopyPlayer(short,short);
  131. WORD QuickRoot(long);
  132. short GetMouse(void);
  133. char LoadIFF(struct IFFGraphic *,struct Screen *,char);
  134. char ClickDelay(short);
  135. void CueJumpAnim(void);
  136. void CheckAngle(short *);
  137. UWORD Rand(UWORD);
  138. short AudioOpenIt(void);
  139. long MyRead(struct FileHandle *,long *,long);
  140. char OpenIt(void);
  141. void CloseIt(void);
  142.  
  143. APTR GetDeviceBlock(ULONG);
  144. void FreeDeviceBlock(struct IOAudio *,BYTE);
  145. void Audio_PerVol(struct IOAudio *,UWORD,UWORD);
  146. void Audio_Write(struct IOAudio *,UBYTE *,UWORD);
  147. void PlaySound(struct audioinfostruct *,short);
  148.  
  149. /******************* Graphics defines ******************/
  150. struct NewScreen ns;
  151. struct NewWindow nw;
  152.  
  153. /* Extra padding for use with tempmask. Must set ballmask to point to */
  154. /* first 'real' byte (8) at start of program */
  155.  
  156. USHORT chip crossmask[5];
  157. USHORT chip mask[37];
  158. USHORT chip mask2[10];
  159. USHORT chip hybridmask[13];
  160. USHORT chip hybridmask2[10];
  161. USHORT chip miniball[8];
  162.  
  163. USHORT *ballmask = &mask[12];
  164. USHORT *ballmask2 = mask2;
  165. USHORT chip tempmask[256];
  166.  
  167. USHORT chip buffer[20];
  168.  
  169. /********************* System defines ************************/
  170. struct Screen         *s,*s2;
  171. struct Window         *w,*w2;
  172. struct RastPort    *rp,*rp2,bufrp;
  173. struct BitMap        *bm,*bm2,bufbm;
  174. struct ViewPort     *vp;
  175. struct ColorMap     *cm;
  176. struct IntuiMessage *msg;
  177. struct FileHandle    *fh;
  178. struct Preferences  prefs;
  179.  
  180. UWORD *colorpalette;
  181.  
  182. char *bp0,*bp1,*bp2,*bp3,*bp4;
  183.  
  184. long oldkeyspeed,oldkeydelay;
  185.  
  186. /******************* Audio Defines ******************/
  187.  
  188. #define SAMPLES 8
  189. #define AM2 106 /* Audio Master II info size */
  190. #define BUFWAVELEN 100
  191.  
  192. enum sound { COLLIDE,STRIKE,BOUNCE,POTTED,CHEER,LONGCHEER,CHANT,CRASH };
  193.  
  194. #define AUDIO_LEN (sizeof(struct IOAudio))
  195. #define PRECIDENCE 127
  196. #define CLOSE_DEVICE 1
  197.  
  198. struct IOAudio *audio[4];
  199. char Channel_Map[] = { 1,2,4,8 },*bufwave;
  200.  
  201. struct audioinfostruct
  202. {
  203.     struct IOAudio *audio;
  204.     char *wave,bufstate,channel,flag;
  205.     long wavelen;
  206.     short volume,period;
  207.     char filename[30];
  208. };
  209.  
  210. #define BUFFER 0
  211. #define RESET  1
  212.  
  213. struct audioinfostruct audioinfo[SAMPLES];
  214.  
  215. /********************* Gameplay defines **********************/
  216. UWORD rgb[32];
  217. UWORD rgb2[32];
  218.  
  219. enum col {
  220.  _back,_leather,_dkleather,_ltbaize,_dkbaize,_dkwalnut,_walnut,_ltwalnut,
  221.  _baize,_yellow,_red,_ltbaize2,_white,_highyel,_highred,_ltbaize3,
  222.  _cross,_ptr17,_ptr18,_ptr19,_cuecol,_ltcuecol,_22,_23,
  223.  _black,_text1,_text2 };
  224.  
  225. enum balltype { white,black,yellow,red, anyball,baize };
  226. char ballpalette[] = { _white,_black,_yellow,_red, 0,_baize };
  227.  
  228. char ball9colour[],ball15colour[];
  229.  
  230. char ballplanes[] = { 4,16,1,2, 0,23 };
  231.  
  232. struct ballstruct
  233. {
  234.     enum balltype colour;
  235.     char potted,justpotted,hasmoved,lasthit,olddx,olddy;
  236.     USHORT x,y;
  237.     short speed,angle,scrnx,scrny,oldscrnx,oldscrny;
  238. };
  239. struct ballstruct ball[16],tempball[16];
  240.  
  241. struct playerstruct
  242. {
  243.     enum balltype colour;
  244.     char goes,wins;
  245.     char nametag;
  246.     short maxpower;
  247.     char cuepulls,skill;
  248. };
  249. struct playerstruct player[8];
  250.  
  251. struct pixelsavestruct
  252. {
  253.     char col;
  254.     short x,y;
  255. };
  256. struct pixelsavestruct pixelsave[32];
  257.  
  258. struct blitdatstruct
  259. {
  260.     short x,y,dx,dy;
  261. };
  262. struct blitdatstruct blitdat,blitdat2;
  263.  
  264. short *memblock, *quicksin, *quickcos;
  265. char *quickarcsin;
  266.  
  267. WORD cueangle=270,cuespeed=MINSPEED,powerdirn=UP,
  268.     spinx,spiny,swerve,swervetotal;
  269.  
  270. USHORT seed; /* random element */
  271.  
  272. short gametype,gamelength,stripper,opponent,
  273.     cueline,cloth,firsthit,turn,dotspacing=8,newbreak,cheer,
  274.     comp1,comp2,foul,endofgame,quitgame,winner,matches,coin,balls,
  275.     packstate,plyrbreak;
  276.  
  277. USHORT pocketx[6];
  278. USHORT pockety[6];
  279.     
  280. char angleused[360];    
  281.  
  282. char joydelay;
  283.  
  284. extern struct Custom far custom;
  285.  
  286. /********* Loader stuff *************/
  287.  
  288. extern struct IFFGraphic /* defined in load.c */
  289. {
  290. char        FileName[30];    /* Name of IFF file */
  291. BYTE        ReqDepth;        /* How many bitplanes wish to be Displayed */  
  292. USHORT    *RGB;        /* RGB colour values, filled by LoadIFF */ 
  293. short    Width;        /* Width of graphic, filled by LoadIFF */ 
  294. short    Height;        /* Height of graphic, filled by LoadIFF */ 
  295. BYTE        Depth;        /* Depth of graphic, filled by LoadIFF */ 
  296. };
  297. extern char arg[8];
  298. struct IFFGraphic tableIFF =  { "fnpool:table.img",5,NULL };
  299.  
  300. UWORD RGBbaize[20];
  301. UWORD RGBball[7];
  302. UWORD RGBroom[16];
  303.  
  304. /********** Strip stuff *****************/
  305.  
  306. struct IFFGraphic roomIFF;
  307. struct IFFGraphic stripIFF[4];
  308.  
  309. struct stripstruct
  310. { short imgx1[4],imgy1[4],imgdx[4],imgdy[4],imgx2[4],imgy2[4],
  311.     textfiletag[5],textx[5],texty[5],textdx[5],textdy[5]; };
  312.  
  313. /******* Message stuff *****************/
  314.  
  315. #define NEW 0
  316. #define FOLLOW 1
  317.  
  318. short cursor;
  319.  
  320. enum msg { MSG_PLACECUEBALL,MSG_FOUL,MSG_WINS,MSG_MICHAEL,MSG_JOSH,
  321.     MSG_CLAIRE,MSG_SALLY,MSG_PLAYER1,MSG_PLAYER2,MSG_QUITTING,
  322.     MSG_VS,MSG_GAME,MSG_OF,MSG_0,MSG_1,MSG_2,MSG_3,MSG_4,MSG_5,
  323.     MSG_GOODSHOT,MSG_SHOTCANCELLED,MSG_BADLUCK,MSG_WELLDONE,
  324.     MSG_QUITGAME,MSG_ISTHECHAMP,MSG_OOOPS };
  325.  
  326. struct messagestruct { short x1,y1,x2,y2; };
  327. struct messagestruct message[];
  328.  
  329. /************************/
  330. char OpenIt()
  331. {
  332.     short i;
  333.     
  334.     if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)))    return(0);
  335.     if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",0))) return(0);
  336.  
  337.     if (!(s2 = OpenScreen(&ns))) return(0);
  338.     if (!(s = OpenScreen(&ns))) return(0);
  339.     nw.Screen = s;
  340.     if (!(w = OpenWindow(&nw))) return(0);
  341.     nw.Screen = s2;
  342.     if (!(w2 = OpenWindow(&nw))) return(0);
  343.     if (!AudioOpenIt()) return(0);
  344.     if (!(memblock = AllocMem(MEMSIZE,MEMF_PUBLIC))) return(0);
  345.     
  346.     cm = GetColorMap(32);
  347.     s->ViewPort.ColorMap = cm;
  348.     s2->ViewPort.ColorMap = GetColorMap(32);
  349.     rp = &s->RastPort; bm = &s->BitMap;
  350.     rp2 = &s2->RastPort; bm2 = &s2->BitMap;
  351.     colorpalette = (UWORD *)cm->ColorTable;
  352.     bp0 = s->BitMap.Planes[0]; bp1 = s->BitMap.Planes[1];
  353.     bp2 = s->BitMap.Planes[2]; bp3 = s->BitMap.Planes[3];
  354.     bp4 = s->BitMap.Planes[4];
  355.     for (i=0; i<32; i++) colorpalette[i] = 0;    
  356.     MakeScreen(s); RethinkDisplay();
  357.  
  358.     InitBitMap(&bufbm,5,320,256);
  359.     for (i=0; i<5; i++) 
  360.         if (!(bufbm.Planes[i] = AllocRaster(320,256))) return(0);
  361.     
  362.     InitRastPort(&bufrp); bufrp.BitMap = &bufbm;
  363.     bufrp.Mask = 31;
  364.     
  365.     while (!(fh = (struct FileHandle *) Open("FNPGRAPHICS:message.img",MODE_OLDFILE)));
  366.  
  367.     Seek((BPTR)fh,8,OFFSET_BEGINNING);
  368.     MyRead(fh,bufbm.Planes[0]+(175*40),(40*78));
  369.     MyRead(fh,bufbm.Planes[1]+(175*40),(40*78));
  370.     Close((BPTR)fh);
  371.     
  372.     GetPrefs(&prefs,sizeof(struct Preferences));
  373.     prefs.KeyRptSpeed.tv_secs = 0;
  374.     oldkeyspeed = prefs.KeyRptSpeed.tv_micro;
  375.     prefs.KeyRptSpeed.tv_micro = 10000;
  376.     prefs.KeyRptDelay.tv_secs = 0;
  377.     prefs.KeyRptDelay.tv_micro = 300000;
  378.     oldkeydelay = prefs.KeyRptDelay.tv_micro;
  379.     prefs.PointerTicks = 1;
  380.     SetPrefs(&prefs,sizeof(struct Preferences),TRUE);
  381.     return(1);
  382. }
  383. /**********************/
  384. void WriteMessage(i,x,y,flag)
  385. short i,x,y,flag;
  386. {
  387.     short dx = 1 + message[i].x2-message[i].x1;
  388.     short dy = 1 + message[i].y2-message[i].y1;
  389.  
  390.     if (flag==NEW) { ScrubMessage(); cursor=5; }
  391.     
  392.     SetWrMsk(rp,31); SetAPen(rp,_black);
  393.     RectFill(rp,x+cursor,7+y,x+cursor+dx,7+y+dy);
  394.  
  395.     BltBitMap(&bufbm,message[i].x1,175 + message[i].y1,bm,x+cursor,7+y,
  396.         dx,dy,0xc0,3,buffer);
  397.  
  398.     cursor += 10 + dx + x;
  399. }
  400. /***********************/
  401. void ScrubMessage()
  402. {
  403.     SetWrMsk(rp,31); SetAPen(rp,_black);
  404.     RectFill(rp,10,12,145,30);
  405. }        
  406. /***********************/
  407. void PlayShot()
  408. {
  409.     short i,volume;
  410.     
  411.     ball[CUE].angle = cueangle+180;
  412.     CheckAngle(&ball[CUE].angle);
  413.     ball[CUE].speed = cuespeed;
  414.     ball[CUE].lasthit = NOHIT;
  415.     firsthit=0; /* Which ball is hit first */
  416.     for (i=0; i<balls; i++) ball[i].justpotted=FALSE;
  417.     DrawCue(OFF); DrawCue(HIT);
  418.  
  419.     if ((volume = 16 + (ball[CUE].speed<<6)/MAXSPEED) > 64) volume = 64;
  420.     PlaySound(&audioinfo[STRIKE],volume);
  421.  
  422.     while(UpdateBallPos()) CheckCollision();
  423.     
  424.     for (i=0; i<balls; i++) if (!ball[i].potted) DrawBall(i,ON);
  425.     
  426.     spinx = 0; spiny = 0; swerve = 0; swervetotal = 0;
  427.     if (gametype==PRACTICE)
  428.     {
  429.         for (i=1; i<balls; i++) if (!ball[i].potted) break;
  430.         if (i==balls) /* No balls left on table */ endofgame=TRUE;
  431.     }
  432.     else
  433.     {
  434.         CheckResult();
  435.         if (player[turn].colour==black && !endofgame && cheer)
  436.             PlaySound(&audioinfo[CHANT],64);
  437.     }
  438.     if (packstate!=RACKED) newbreak=FALSE;
  439.  
  440.     if (packstate==OPEN)
  441.     {
  442.         for (i=1; i<balls; i++) if (!ball[i].hasmoved) break;        
  443.         if (i==balls) packstate=SPREAD;
  444.     }
  445.     cuespeed=MINSPEED;
  446.     if (endofgame) { DrawCue(ON); return; }
  447.     CheckWhitePotted();
  448.     WriteMessage(player[turn].nametag,5,5,NEW);
  449.     Delay(20); DrawCue(ON);
  450. }
  451. /**********************/
  452. void CheckWhitePotted()
  453. {
  454.     short returnhit=FALSE,angle,hyp;
  455.     
  456.     if (ball[CUE].potted)
  457.     {
  458.         WriteMessage(MSG_PLACECUEBALL,5,5,NEW);    Delay(50);
  459.         
  460.         ball[CUE].potted = FALSE;
  461.         ball[CUE].x = (TABLELENGTH/4);
  462.         ball[CUE].y = (TABLEWIDTH/2 - BASE*3) + Rand(BASE*6);
  463.         ball[CUE].speed = 0;
  464.  
  465.         while(TouchingBall(CUE)!=NOHIT)
  466.         {
  467.             /* White ball has been placed over another ball! */
  468.             
  469.             angle = Rand(180);
  470.             hyp = Rand(SEMICIRCRAD);
  471.                 
  472.             ball[CUE].x = TABLELENGTH/4 -
  473.                          quicksin[angle]*hyp/BASE;
  474.             ball[CUE].y = TABLEWIDTH/2 +
  475.                          quickcos[angle]*hyp/BASE;
  476.         }
  477.         ball[CUE].scrnx = ball[CUE].x/BASE;
  478.         ball[CUE].scrny = ball[CUE].y/BASE;
  479.  
  480.         DrawBall(CUE,ON);
  481.         if (!(gametype == DEMO || (gametype==PLYR1 && turn==COMPLYR)))
  482.         while(!returnhit)
  483.         {
  484.             short dx,dy,opp,adj;
  485.                         
  486.             dx=0; dy=0;
  487.             switch (GetInput())
  488.             {    
  489.                 case 76: dy=BASE; break;
  490.                 case 77: dy=-BASE; break;
  491.                 case 78: dx=BASE; break;
  492.                 case 79: dx=-BASE; break;
  493.                 case 68: returnhit = TRUE; break;
  494.             }
  495.             WaitTOF(); DrawBall(CUE,OFF);
  496.             
  497.             opp = ((ball[CUE].x+=dx) - TABLELENGTH/4)/BASE;
  498.             adj = ((ball[CUE].y+=dy) - TABLEWIDTH/2)/BASE;
  499.             ball[CUE].scrnx = ball[CUE].x/BASE;
  500.             ball[CUE].scrny = ball[CUE].y/BASE;
  501.             
  502.             if (opp > 0 ||
  503.                 QuickRoot(opp*opp + adj*adj) > SEMICIRCRAD/BASE ||
  504.                 TouchingBall(CUE)!=NOHIT)
  505.                 { ball[CUE].x-=dx; ball[CUE].y-=dy; }
  506.             DrawBall(CUE,ON);
  507.         }
  508.         ball[CUE].oldscrnx = ball[CUE].scrnx;
  509.         ball[CUE].oldscrny = ball[CUE].scrny;
  510.     }
  511. }
  512. /**********************/
  513. void CopyPlayer(from,to)
  514. short from,to;
  515. {
  516.     player[to].nametag = player[from].nametag;
  517.     player[to].maxpower = player[from].maxpower;
  518.     player[to].cuepulls = player[from].cuepulls;
  519.     player[to].skill = player[from].skill;
  520.     player[to].wins = player[from].wins;
  521. }    
  522. /**********************/
  523. void SuperImpose(srcrp,x0,y0,destrp,x1,y1,dx,dy,transp,offset)
  524. short x0,y0,dx,dy,x1,y1,transp,offset;
  525. struct RastPort *srcrp,*destrp;
  526. {
  527.     register short x,y,pixel;
  528.     
  529.     for (y=0; y < dy; y++)
  530.     for (x=0; x < dx; x++)
  531.     if ((pixel = ReadPixel(srcrp,x0+x,y0+y)) != transp)
  532.     { SetAPen(destrp,offset+pixel); WritePixel(destrp,x1+x,y1+y); }
  533. }
  534. /**********************/
  535. short ChangeSpin()
  536. {
  537.     short input,retnval=TRUE,new=FALSE,spinx2=spinx,spiny2=spiny;
  538.     
  539.     rp->Mask = 31; DrawCross(ON);
  540.  
  541.     do
  542.     {
  543.         input = GetInput();
  544.         switch(input)
  545.         {
  546.             case UCSR: if (spiny < 400) { spiny2=spiny+100; new=1; }
  547.                     break;
  548.             case DCSR: if (spiny > -800) { spiny2=spiny-100; new=1; }
  549.                     break;
  550.             case RCSR: if (spinx < 600) { spinx2=spinx+100; new=2; }
  551.                     break; 
  552.             case LCSR: if (spinx > -600) { spinx2=spinx-100; new=2; }
  553.                     break;
  554.             case ESC: spinx2=0; spiny2=0; new=1; retnval=FALSE; break;
  555.         }        
  556.         switch (new)
  557.         {
  558.             case 2:
  559.             {
  560.                 short tempx = spinx,tempy = spiny;
  561.                 
  562.                 DrawCue(OFF); spinx=spinx2; spiny=spiny2; DrawCue(ON);
  563.                 spinx = tempx; spiny = tempy;
  564.             }
  565.             case 1:
  566.                 DrawCross(OFF); spinx=spinx2; spiny=spiny2;
  567.                 DrawCross(ON); new=FALSE; break;
  568.         }
  569.  
  570.     } while (input!=RETURN && input!=ESC);
  571.     
  572.     DrawCross(OFF);
  573.     swerve = abs(spiny) * spinx / 4800;
  574.     return retnval;
  575. }
  576. /**********************/
  577. void DrawCross(status)
  578. short status;
  579. {
  580.     blitdat2.x = 157+spinx/100;
  581.     blitdat2.y = 14-spiny/100;
  582.     blitdat2.dx = 5; blitdat2.dy = 5;
  583.  
  584.     if (status==OFF)
  585.     {
  586.         WaitBeam(40);
  587.         BltBitMap(&bufbm,0,85,bm,blitdat2.x,blitdat2.y,
  588.             blitdat2.dx,blitdat2.dy,0xc0,31,buffer);
  589.     }
  590.     else
  591.     {
  592.         SetAPen(rp,_cross);        
  593.         BltBitMap(bm,blitdat2.x,blitdat2.y,&bufbm,
  594.             0,85,blitdat2.dx,blitdat2.dy,0xc0,31,buffer);
  595.     
  596.         BltPattern(rp,crossmask,
  597.             157+spinx/100,14-spiny/100,
  598.             161+spinx/100,18-spiny/100,2);
  599.     }
  600. }
  601. /**********************/
  602. void ChangePower()
  603. {
  604.     short offset;
  605.     
  606.     if (powerdirn==DOWN)
  607.     {
  608.         if ((cuespeed-=(SPEEDINC/2)) < MINSPEED)
  609.         { powerdirn=UP; cuespeed=MINSPEED; }
  610.     }
  611.     else if ((cuespeed+=SPEEDINC) > MAXSPEED)
  612.     { powerdirn=DOWN; cuespeed=MAXSPEED; }
  613.     
  614.     offset = (cuespeed*16)/BASESP;
  615.     
  616.     rp->Mask = 31;
  617.     WaitBeam(21);
  618.     SetAPen(rp,_back); RectFill(rp,201+offset,18,265,21);
  619.     SetAPen(rp,_white); RectFill(rp,199,18,200+offset,21);
  620. }
  621. /**********************/
  622. void WaitBeam(y)
  623. short y;
  624. {
  625.     short vert;
  626.     while(1)
  627.     {
  628.         vert = VBeamPos();
  629.         if (vert > y+40 && vert < y+70) break;
  630.     }
  631. }
  632. /**********************/
  633. void MoveCue(dirn,increment)
  634. short dirn,increment;
  635. {
  636.     DrawCue(OFF);
  637.     
  638.     if (dirn==CLOCKWISE) cueangle += (increment==SMALL)? 1:10;
  639.     else cueangle -= (increment==SMALL)? 1:10;
  640.     CheckAngle(&cueangle);
  641.     DrawCue(ON);
  642. }    
  643. /**********************/
  644. void DoAssigns()
  645. {    
  646. /*    short i; */
  647.  
  648.     quicksin = memblock;
  649.     quickcos = quicksin+361;
  650.     quickarcsin = quickcos+361;
  651.     
  652. /*
  653.     for (i=0; i<361; i++)
  654.     {
  655.         quicksin[i] = sin((double)i * PI / 180.0) * (double)BASE;
  656.         quickcos[i] = cos((double)i * PI / 180.0) * (double)BASE;
  657.     }
  658.     for (i=0; i<5001; i++)
  659.         quickarcsin[i] = asin((double)i / 5000.0) * 180.0 / PI;
  660. */
  661.     while (!(fh = (struct FileHandle *)Open("FNP:trig.dat",MODE_OLDFILE)));
  662.     
  663.     Read((BPTR)fh,quicksin,361*2);
  664.     Read((BPTR)fh,quickcos,361*2);
  665.     Read((BPTR)fh,quickarcsin,5001);
  666.     Close((BPTR)fh);
  667. }
  668. /**********************/
  669. short GetInput()
  670. {
  671.     short code = NULL,code2;
  672.     ULONG joy = (ULONG)custom.joy1dat;        /* joystick info */
  673.  
  674.     if (joydelay==1) { Delay(10); joydelay=2; }
  675.     else if (!(gametype==PLYR2 && turn == 1))
  676.     {
  677.         if ((long)(joy & 768) == 512L) code = LCSR;    /* Up-left */
  678.         else if ((long)(joy & 3) == 2L) code = RCSR; /* Down-right */
  679.         else if ((long)(joy & 3) == 3L) code = RCSR;
  680.         else if ((long)(joy & 768L) == 768L) code = LCSR;
  681.         else if ((long)(joy & 768) == 256L) code = UCSR;
  682.         else if ((long)(joy & 3) == 1L) code = DCSR;
  683.         else joydelay = 0;
  684.                 
  685.         if (!joydelay && code) joydelay=1;
  686.         
  687.         while (!(*(char *)JOYFIRE & 0x80)) code = RETURN;
  688.         if (code==RETURN) Delay(20); /* Joystick fire */
  689.     }
  690.  
  691.     if (!(msg = (struct IntuiMessage *)GetMsg(w->UserPort)))
  692.          return code;
  693.     do
  694.     {
  695.         code2 = msg->Code;
  696.         ReplyMsg((struct Message *)msg);
  697.     
  698.     } while((msg = (struct IntuiMessage *)GetMsg(w->UserPort)) &&
  699.         code2!=ESC);
  700.  
  701.     if (gametype==PLYR2 && turn == 0)
  702.     {
  703.         switch (code2)
  704.         {
  705.             case UCSR:
  706.             case DCSR:
  707.             case LCSR:
  708.             case RCSR:
  709.             case RETURN: return code;
  710.         }
  711.     }
  712.     return code2;
  713. }
  714. /**********************/
  715. char UpdateBallPos()
  716. {
  717.     short i,j,x1,y1,x2,y2,dx,dy;
  718.     char ballsmoving = FALSE;
  719.     
  720.     for(i=0; i<balls; i++) /* Update ball position */
  721.     if (!ball[i].potted && ball[i].speed > 0)
  722.     {
  723.         ballsmoving=TRUE; ball[i].hasmoved=TRUE;
  724.         ball[i].x += ball[i].speed * quicksin[ball[i].angle] / BASESP;
  725.         ball[i].y += ball[i].speed * quickcos[ball[i].angle] / BASESP;
  726.         
  727.         if ((ball[i].scrnx = ball[i].x/BASE) - ball[i].oldscrnx |
  728.             (ball[i].scrny = ball[i].y/BASE) - ball[i].oldscrny)
  729.         {
  730.             if (CheckPotted(i))
  731.             { ball[i].potted = TRUE; ball[i].justpotted = TRUE; }
  732.             else CheckBounce(i);
  733.             
  734.             if (ball[i].potted)
  735.             {
  736.                 ball[i].scrnx = ball[i].oldscrnx;
  737.                 ball[i].scrny = ball[i].oldscrny;
  738.                 DrawBall(i,OFF);
  739.             }
  740.             else
  741.             {
  742.                 USHORT *tmask = tempmask+(i<<4);    
  743.                 
  744.                 x1 = (X1CORNER-8) + ball[i].oldscrnx;
  745.                 y1 = (Y2CORNER-7) - ball[i].oldscrny;
  746.                 x2 = (X1CORNER-8) + ball[i].scrnx;
  747.                 y2 = (Y2CORNER-7) - ball[i].scrny;
  748.                 dx = x2-x1; dy = y2-y1;
  749.  
  750.                 if (dx != ball[i].olddx || dy != ball[i].olddy)
  751.                 {
  752.                     register USHORT *quickmask = ballmask;
  753.             
  754.                     if (dx >= 0) for (j=0; j<13; j++)
  755.                     tmask[j] = quickmask[j] ^
  756.                         (quickmask[j] & (*(quickmask+j-dy) >> dx));
  757.         
  758.                     else for (j=0; j<13; j++)
  759.                     tmask[j] = quickmask[j] ^
  760.                         (quickmask[j] & (*(quickmask+j-dy) << -dx));
  761.                 
  762.                     ball[i].olddx = dx; ball[i].olddy = dy;
  763.                 }                
  764.  
  765.                 if (ball[i].colour != white)
  766.                 {
  767.                     register char *ptr = bp2 + (y1+3)*40 + ((x1+7)>>3);
  768.                     register short data = 128 >> ((x1+7) % 8);
  769.                     
  770.                     ptr[0] &= ~data; ptr[80] &= ~data;
  771.                     if (data==1)
  772.                     { ptr[40] &= 252; ptr[41] &= 127; }
  773.                     else if (data==128)
  774.                     { ptr[40] &= 63; ptr[39] &= 254; }
  775.                     else ptr[40] &= ~(data + (data>>1) + (data<<1));
  776.                 }
  777.                 DrawBallDirect(ball[i].colour,x2,y2);
  778.                 SetAPen(rp,_baize);
  779.                 rp->Mask = ballplanes[ball[i].colour];
  780.                 BltPattern(rp,tmask,x1,y1,x1+15,y1+12,2);
  781.  
  782.                 ball[i].oldscrnx = ball[i].scrnx;
  783.                 ball[i].oldscrny = ball[i].scrny;
  784.             }
  785.         }
  786.         if (balls==10) ball[i].speed-=(FRICTION/2);
  787.         else ball[i].speed-=FRICTION;
  788.         if (ball[i].speed < 0) ball[i].speed = 0;
  789.     }
  790.     spinx -= (spinx > 0)? SPINFRICTION:-SPINFRICTION;
  791.     spiny -= (spiny > 0)? SPINFRICTION:-SPINFRICTION;
  792.     if ((swervetotal+=abs(swerve)) > 99)
  793.     {
  794.         ball[CUE].angle += (swerve > 0)? 1:-1;
  795.         CheckAngle(&ball[CUE].angle);
  796.         swervetotal-=100;
  797.     }
  798.     swerve -= (swerve > 0)? 1:-1;
  799.     return ballsmoving;
  800. }
  801. /**********************/
  802. short CheckPotted(i)
  803. short i;
  804. {
  805.     BOOL potted = FALSE;
  806.     short volume;
  807.     register USHORT x = ball[i].x, y = ball[i].y;
  808.         
  809.     if (ball[i].potted) return(FALSE);
  810.     
  811.     if (x > (TABLELENGTH-BALLRADIUS) &&
  812.         (y < POCKET || y > (TABLEWIDTH-POCKET)))
  813.             potted = TRUE;
  814.     
  815.     else if (x < BALLRADIUS && (y < POCKET || y > (TABLEWIDTH-POCKET)))
  816.         potted = TRUE;
  817.                         
  818.     else if (y < BALLRADIUS &&
  819.             (x < POCKET || 
  820.             (x > (TABLELENGTH/2 - POCKET/2) &&
  821.             x < (TABLELENGTH/2 + POCKET/2)) ||
  822.             x > (TABLELENGTH-POCKET)))
  823.                 potted = TRUE;
  824.                 
  825.     else if (y > (TABLEWIDTH-BALLRADIUS) &&
  826.             (x < POCKET ||
  827.             (x > (TABLELENGTH/2 - POCKET/2) &&
  828.              x < (TABLELENGTH/2 + POCKET/2)) ||
  829.              x > (TABLELENGTH-POCKET)))
  830.                 potted = TRUE;
  831.  
  832.     if (potted)
  833.     {
  834.         if ((volume = 16 + (ball[i].speed<<6)/MAXSPEED) > 64) volume = 64;
  835.         PlaySound(&audioinfo[POTTED],volume);
  836.         if (ball[i].speed > (MAXSPEED*5/8) && !(Rand(4)))
  837.         {
  838.             ball[i].angle+=180; CheckAngle(&ball[i].angle);
  839.             ball[i].x += ball[i].speed * quicksin[ball[i].angle] / BASESP;
  840.             ball[i].y += ball[i].speed * quickcos[ball[i].angle] / BASESP;
  841.             ball[i].scrnx = ball[i].x/BASE; ball[i].scrny = ball[i].y/BASE;
  842.             ball[i].speed >>= 2; ball[i].lasthit=NOHIT; potted=FALSE;
  843.         }
  844.     }
  845.     return(potted);
  846. }
  847. /**********************/
  848. void CheckBounce(i)
  849. short i;
  850. {
  851.     short bounce=FALSE,volume;
  852.     register USHORT x = ball[i].x, y = ball[i].y;
  853.     register short angle = ball[i].angle;
  854.     
  855.     if (ball[i].potted) return;
  856.     
  857.     if (x < BALLRADIUS && angle > 180)
  858.     { angle=360-ball[i].angle; bounce=TRUE; }
  859.  
  860.     else if (x > (TABLELENGTH-BALLRADIUS) && angle < 180)
  861.     { angle=360-ball[i].angle; bounce=TRUE; }
  862.     
  863.     else if (y < BALLRADIUS && angle < 270 && angle > 90)
  864.     {
  865.         if (angle <= 180) angle=180-ball[i].angle;
  866.         else angle=540-ball[i].angle; bounce=TRUE;
  867.     }
  868.     else if (y > (TABLEWIDTH-BALLRADIUS) && (angle > 270 || angle < 90))
  869.     {
  870.         if (angle <= 180) angle=180-ball[i].angle;
  871.         else angle=540-ball[i].angle; bounce=TRUE;
  872.     }
  873.     if (bounce)
  874.     {
  875.         if ((volume = 16 + (ball[i].speed<<6)/MAXSPEED) > 64) volume = 64;
  876.         PlaySound(&audioinfo[BOUNCE],volume);
  877.         if (ball[CUE].speed > (MAXSPEED*3/4) && spiny < -600 && !(Rand(3)))
  878.             CueJumpAnim();
  879.  
  880.         ball[i].angle = angle;
  881.         ball[i].x += ball[i].speed * quicksin[ball[i].angle] / BASESP;
  882.         ball[i].y += ball[i].speed * quickcos[ball[i].angle] / BASESP;
  883.         ball[i].scrnx = ball[i].x/BASE; ball[i].scrny = ball[i].y/BASE;
  884.         if (ball[i].scrnx < (BALLRADIUS/BASE)) ball[i].scrnx = (BALLRADIUS/BASE);
  885.         else if (ball[i].scrnx > ((TABLELENGTH-BALLRADIUS)/BASE))
  886.             ball[i].scrnx = ((TABLELENGTH-BALLRADIUS)/BASE);
  887.         if (ball[i].scrny < (BALLRADIUS/BASE)) ball[i].scrny = (BALLRADIUS/BASE);
  888.         else if (ball[i].scrny > ((TABLEWIDTH-BALLRADIUS)/BASE))
  889.             ball[i].scrny = ((TABLEWIDTH-BALLRADIUS)/BASE);
  890.         ball[i].speed = ((ball[i].speed << 3) - ball[i].speed) >> 3; 
  891.         ball[i].lasthit = NOHIT;
  892.         if (i==CUE)
  893.         {
  894.             ball[CUE].angle -= spinx / 25;
  895.             spinx = 0; spiny = 0; swerve = 0;
  896.             CheckAngle(&ball[CUE].angle);
  897.         }
  898.         if (packstate==BROKEN) packstate=OPEN; /* can now hear all collisions */
  899.     }
  900. }
  901. /**********************/
  902. short GetMouse()
  903. {
  904.     short status=0;
  905.  
  906.     UBYTE *leftmouse = (UBYTE *)0xbfe001;
  907.     UWORD *rightmouse = (UWORD *)0xdff016;
  908.     
  909.     if (!(*leftmouse & 0x40)) status |= LMOUSE;
  910.     if ((*rightmouse & 0x0400) != 0x0400) status |= RMOUSE;
  911.     return status;
  912. }
  913. /****************/
  914. void SetUpTable()
  915. {
  916.     short i,j,k,offset,oldoffset=0;
  917.     
  918.     for (i=0; i<balls; i++) if (!ball[i].potted && ball[i].x)
  919.     {
  920.         ball[i].x = ball[i].oldscrnx*BASE;
  921.         ball[i].y = ball[i].oldscrny*BASE;
  922.         DrawBall(i,OFF);
  923.     }
  924.     ball[CUE].x = (TABLELENGTH/4);
  925.     ball[CUE].y = (TABLEWIDTH/2 - BASE*3) + Rand(BASE*6);
  926.     
  927.     for (i=0,k=1; i<5; i++)
  928.     for (j=0; j<=i; j++,k++)
  929.     {
  930.         ball[k].x = (PLACEPACK-BASE) + PACKHORIZSEP*i;
  931.         ball[k].y = (TABLEWIDTH / 2) + (BALLDIAMETER *j) -
  932.                 (BALLDIAMETER * i / 2) - BASE;
  933.         ball[k].x += Rand((BASE/2));
  934.         ball[k].y += Rand((BASE/2));
  935.     }
  936.     
  937.     if (balls==10)
  938.     {
  939.         ball[7].y+=BALLDIAMETER; ball[8].y+=BALLDIAMETER;
  940.         ball[9].x+=PACKHORIZSEP; ball[9].y-=(BALLDIAMETER/2);
  941.         for (i=0; i<10; i++) ball[i].colour = ball9colour[i];
  942.     }    
  943.     else for (i=0; i<16; i++) ball[i].colour = ball15colour[i];
  944.     
  945.     BltBitMap(&bufbm,200,0,bm,182,107,71,79,0xc0,31,buffer);
  946.     if (gametype!=PRACTICE && cheer) PlaySound(&audioinfo[CHEER],64);
  947.  
  948.     for (i=0; i<balls; i++)
  949.     {
  950.         ball[i].potted = FALSE; ball[i].speed = 0;
  951.         ball[i].lasthit = NOHIT;
  952.         ball[i].hasmoved = 0;
  953.         ball[i].scrnx = ball[i].x/BASE;
  954.         ball[i].scrny = ball[i].y/BASE;
  955.         ball[i].oldscrnx = ball[i].scrnx;
  956.         ball[i].oldscrny = ball[i].scrny;
  957.         ball[i].olddx = -99; ball[i].olddy = -99;
  958.         DrawBall(i,ON);
  959.     }
  960.     if (balls==16) for (j=0,k=25; j<5; j++,k-=5)
  961.     {
  962.         for (i=0; i<=360; i+=30)
  963.         {
  964.             offset = quicksin[i]*k/BASE;
  965.             WaitBeam(185);
  966.             BltBitMap(bm,(182-15)-oldoffset,107,
  967.                 bm,(182-15)-offset,107,(71+30),79,0xc0,31,buffer);
  968.             if (i==90 || i==270) PlaySound(&audioinfo[COLLIDE],64);
  969.             oldoffset = offset;
  970.         }
  971.     }
  972.     Delay(30);
  973.     BltBitMap(bm,100,107,bm,182,107,71,79,0xc0,31,buffer);
  974.     for (i=1; i<balls; i++) DrawBall(i,ON);
  975.         
  976.     if (coin==-1) coin = Rand(2);
  977.     coin = 1-coin; turn = coin;
  978.     if (balls==16)
  979.     { player[0].colour = anyball; player[1].colour = anyball; }
  980.     else { player[0].colour = red; player[1].colour = red; }
  981.     
  982.     player[turn].goes = 1;
  983.     
  984.     if (gametype!=PRACTICE) DrawBall(player[turn].colour,ICON);    
  985.     cueangle = 270; DrawCue(ON);
  986.     packstate=RACKED; plyrbreak=0; newbreak=TRUE;
  987. }
  988. /**********************/
  989. void CheckBallDrag()
  990. {
  991.     short i,x,y,button;
  992.     
  993.     if (button = GetMouse())
  994.     {
  995.         x = s->MouseX; y = s->MouseY;
  996.  
  997.         for (i=0; i<balls; i++)
  998.         {
  999.             if (!ball[i].potted &&
  1000.                 x > ball[i].scrnx+(X1CORNER-7) &&
  1001.                 x < ball[i].scrnx+(X1CORNER+8) &&
  1002.                 y > (Y2CORNER-8)-ball[i].scrny &&
  1003.                 y < (Y2CORNER+8)-ball[i].scrny &&
  1004.                 ReadPixel(rp,x,y) != _baize)
  1005.             {
  1006.                 DrawCue(OFF);
  1007.                 if (button==RMOUSE && i!=CUE)
  1008.                 {
  1009.                     DrawBall(i,OFF);
  1010.                     ball[i].potted = TRUE;
  1011.                     PlaySound(&audioinfo[POTTED],64);
  1012.                 }
  1013.                 else if (button==LMOUSE)
  1014.                 {
  1015.                     PlaySound(&audioinfo[COLLIDE],64);
  1016.                     while (GetMouse() == LMOUSE)
  1017.                     {
  1018.                         short oldx,oldy;
  1019.                     
  1020.                         x = s->MouseX; y = s->MouseY;
  1021.                         if (x < (X1CORNER+7)) x = (X1CORNER+7);
  1022.                         if (x > (X2CORNER-8)) x = (X2CORNER-8);
  1023.                         if (y < (Y1CORNER+8)) y = (Y1CORNER+8);
  1024.                         if (y > (Y2CORNER-7)) y = (Y2CORNER-7);
  1025.                         {
  1026.                             oldx = ball[i].x; oldy = ball[i].y;
  1027.                             ball[i].x = (x-X1CORNER)*BASE;
  1028.                             ball[i].y = (Y2CORNER-y)*BASE;
  1029.                             if (TouchingBall(i)==NOHIT)
  1030.                             {
  1031.                                 WaitBeam(y+7); DrawBall(i,OFF);
  1032.                                 ball[i].scrnx = ball[i].x/BASE;
  1033.                                 ball[i].scrny = ball[i].y/BASE;
  1034.                                 DrawBall(i,ON);
  1035.                             }
  1036.                             else { ball[i].x = oldx; ball[i].y = oldy; }
  1037.                         }
  1038.                     }
  1039.                 }
  1040.                 ball[i].oldscrnx = ball[i].scrnx;
  1041.                 ball[i].oldscrny = ball[i].scrny;
  1042.                 DrawCue(ON); while (GetMouse());
  1043.             }
  1044.         }
  1045.         if (button==(LMOUSE|RMOUSE))
  1046.         {
  1047.             for (i=1; i<balls; i++)
  1048.             if (ball[i].potted &&
  1049.                 x > (X1CORNER+6) && x < (X2CORNER-8) &&
  1050.                 y > (Y1CORNER+8) && y < (Y2CORNER-6))
  1051.             {
  1052.                 ball[i].potted = FALSE;
  1053.                 ball[i].x = (x-X1CORNER)*BASE;
  1054.                 ball[i].y = (Y2CORNER-y)*BASE;
  1055.                 if (TouchingBall(i)==NOHIT)
  1056.                 {
  1057.                     DrawCue(OFF);
  1058.                     ball[i].scrnx = ball[i].x/BASE;
  1059.                     ball[i].scrny = ball[i].y/BASE;
  1060.                     ball[i].oldscrnx = ball[i].scrnx;
  1061.                     ball[i].oldscrny = ball[i].scrny;
  1062.                     ball[i].speed = 0;
  1063.                     WaitBeam(y+7); DrawBall(i,ON);
  1064.                     PlaySound(&audioinfo[COLLIDE],64);
  1065.                     DrawCue(ON); break;
  1066.                 }
  1067.                 else ball[i].potted = TRUE;
  1068.             }
  1069.             while (GetMouse());
  1070.         }
  1071.     }
  1072. }
  1073.  
  1074. /**********************/
  1075. void CheckCollision()
  1076. {
  1077.     char i;
  1078.     BOOL collision;
  1079.  
  1080.     for(i=0; i<balls; i++) /* Check for collisions */
  1081.     {
  1082.         register short x1 = ball[i].scrnx + SCRNBALLDIAMETER;
  1083.         register short y1 = ball[i].scrny + SCRNBALLDIAMETER;
  1084.         register short x2 = x1 - (SCRNBALLDIAMETER*2);
  1085.         register short y2 = y1 - (SCRNBALLDIAMETER*2);
  1086.         register char j;
  1087.         
  1088.         for(j=i+1; j<balls; j++)
  1089.         {
  1090.             /* Quick bounding box test to see if balls touch */
  1091.             if (ball[j].scrnx < x1 && ball[j].scrnx > x2 &&
  1092.                 ball[j].scrny < y1 && ball[j].scrny > y2)
  1093.             {
  1094.                 short dx = ball[j].x - ball[i].x;
  1095.                 short dy = ball[j].y - ball[i].y;
  1096.             
  1097.                 if (dx*dx + dy*dy < (BALLDIAMETER*BALLDIAMETER))
  1098.                 {
  1099.                     collision=TRUE;
  1100.                 
  1101.                     /* Bug-fix to stop multiple collisions for same balls */
  1102.                     if (ball[j].lasthit==i && ball[i].lasthit==j)
  1103.                         collision=FALSE;
  1104.                 
  1105.                     /* Balls are both stationary */
  1106.                     else if (!ball[i].speed && !ball[j].speed)
  1107.                         collision=FALSE;
  1108.  
  1109.                     /* Balls must be unpotted */
  1110.                     else if (ball[j].potted || ball[i].potted)
  1111.                         collision=FALSE;
  1112.  
  1113.                     if (collision) MakeCollision(i,j);
  1114.                 }
  1115.             }
  1116.         }
  1117.     }
  1118. }
  1119.  
  1120. /**********************/
  1121. void DrawBallDirect(col,x,y)
  1122. short col,x,y;
  1123. {
  1124.     SetAPen(rp,ballpalette[col]);
  1125.     rp->Mask = ballplanes[col];
  1126.     BltPattern(rp,ballmask,x,y,x+15,y+12,2);
  1127.  
  1128.     if (col==baize) return;
  1129.  
  1130.     if (col != white)
  1131.     {
  1132.         register char *ptr = bp2 + (y+3)*40 + ((x+7)>>3);
  1133.         register short data = 128 >> ((x+7) % 8);
  1134.  
  1135.         ptr[0] |= data; ptr[80] |= data;
  1136.         if (data==1) { ptr[40] |= 3; ptr[41] |= 128; }
  1137.         else if (data==128) { ptr[40] |= 192; ptr[39] |= 1; }
  1138.         else ptr[40] |= data + (data>>1) + (data<<1);
  1139.     }                        
  1140. }
  1141. /**********************/
  1142. void DrawBall(i,status)
  1143. short i,status;
  1144. {
  1145.     short x = X1CORNER - 8 + ball[i].scrnx,
  1146.          y = Y2CORNER - 7 - ball[i].scrny;
  1147.     
  1148.     if (status==ON) DrawBallDirect(ball[i].colour,x,y);
  1149.     else if (status==OFF) DrawBallDirect(baize,x,y);
  1150.     else if (status==ICON)
  1151.     {
  1152.         DrawBallDirect(baize,287,11);
  1153.         
  1154.         switch(i)
  1155.         {
  1156.             case red:
  1157.             case yellow:
  1158.             case black:
  1159.                 DrawBallDirect(i,287,11);
  1160.                 break;
  1161.                 
  1162.             case anyball:
  1163.                 DrawBallDirect(red,287,11);
  1164.                 ballmask = hybridmask; /* ballmask2 = hybridmask2; */
  1165.                 DrawBallDirect(baize,287,11);
  1166.                 DrawBallDirect(yellow,287,11);
  1167.                 ballmask = &mask[12]; /* ballmask2 = mask2; */ break;
  1168.         }
  1169.     }        
  1170. }
  1171. /**********************/
  1172. void CheckResult()
  1173. {
  1174.     short i,redpot=0,yellowpot=0,whitepot=0,blackpot=0,
  1175.         redsleft=FALSE,yellowsleft=FALSE;
  1176.  
  1177.     foul=FALSE;
  1178.     
  1179.     for (i=0; i<balls; i++)
  1180.     {
  1181.         if (ball[i].justpotted) switch (ball[i].colour)
  1182.         {
  1183.             case red:        redpot++; break;
  1184.             case yellow:    yellowpot++; break;
  1185.             case black:    blackpot++; break;
  1186.             case white:    whitepot++; break;
  1187.         }
  1188.         
  1189.         if (!ball[i].potted) switch (ball[i].colour)
  1190.         {
  1191.             case red:        redsleft=TRUE; break;
  1192.             case yellow:    yellowsleft=TRUE; break;
  1193.         }
  1194.     }    
  1195.     switch(player[turn].colour)
  1196.     {
  1197.         case black:
  1198.             if (blackpot)
  1199.             {
  1200.                 endofgame=TRUE;
  1201.                 if (whitepot) foul=TRUE;
  1202.             }
  1203.             if (redpot || yellowpot) foul=TRUE;
  1204.             if (ball[firsthit].colour!=black) foul=TRUE;
  1205.             if (!blackpot) player[turn].goes=0;
  1206.             break;
  1207.             
  1208.         case red: /* Includes 9 ball variations... */
  1209.             if (!redsleft)
  1210.             {
  1211.                 player[turn].colour=black;
  1212.                 if (balls==10) player[1-turn].colour=black;
  1213.             }
  1214.             if (!yellowsleft && balls==16) player[1-turn].colour=black;
  1215.             if (!redpot) player[turn].goes--;
  1216.             if (blackpot)
  1217.             {
  1218.                 endofgame=TRUE;
  1219.                 if (!newbreak) foul=TRUE;
  1220.                 break;
  1221.             }
  1222.             if (yellowpot) foul=TRUE;
  1223.             if (ball[firsthit].colour!=red) foul=TRUE;
  1224.             break;
  1225.         case yellow:
  1226.             if (!yellowsleft) player[turn].colour=black;
  1227.             if (!redsleft) player[1-turn].colour=black;
  1228.             if (!yellowpot) player[turn].goes--;
  1229.             if (blackpot) { foul=TRUE; endofgame=TRUE; }
  1230.             if (redpot) foul=TRUE;
  1231.             if (ball[firsthit].colour!=yellow) foul=TRUE;
  1232.             break;
  1233.         case anyball:
  1234.             if (blackpot)
  1235.             {
  1236.                 endofgame=TRUE;
  1237.                 if (!newbreak) foul=TRUE;
  1238.                 break;
  1239.             }
  1240.             if (whitepot) foul=TRUE;
  1241.             else if (ball[firsthit].colour != red &&
  1242.                 ball[firsthit].colour != yellow) foul=TRUE;
  1243.             else if (yellowpot && !redpot)
  1244.             { player[turn].colour=yellow; player[1-turn].colour=red; }
  1245.             else if (redpot && !yellowpot)
  1246.             { player[turn].colour=red; player[1-turn].colour=yellow; }
  1247.             else if (!redpot && !yellowpot) player[turn].goes--;
  1248.             break;    
  1249.     }
  1250.     if (whitepot) foul=TRUE;
  1251.     if (endofgame) winner = (foul)? winner = 1-turn:turn;
  1252.     
  1253.     if (foul)
  1254.     {
  1255.         turn=1-turn; plyrbreak = 0;
  1256.         if (player[turn].colour==black) player[turn].goes = 1;
  1257.         else player[turn].goes = 2;
  1258.         for (i=0; i<3; i++)
  1259.         {
  1260.             WriteMessage(MSG_FOUL,40,5,NEW); Delay(20);
  1261.             ScrubMessage(); Delay(10);
  1262.             if (GetInput() == RETURN) break;
  1263.         }
  1264.     }
  1265.     else if (player[turn].goes==0)
  1266.     {
  1267.         if (plyrbreak > 2 && cheer) PlaySound(&audioinfo[CHEER],32);
  1268.         turn=1-turn; plyrbreak = 0; player[turn].goes = 1;
  1269.     }
  1270.     else if ((redpot>1 || yellowpot>1 ||
  1271.         (!ball[firsthit].potted && (redpot || yellowpot))) &&
  1272.         !newbreak)
  1273.     {
  1274.         plyrbreak++; WriteMessage(MSG_GOODSHOT,5,5,NEW);
  1275.         if (cheer) PlaySound(&audioinfo[CHEER],64); Delay(50);
  1276.     }
  1277.     else plyrbreak++;
  1278.     
  1279.     if (gametype!=PRACTICE) DrawBall(player[turn].colour,ICON);
  1280. }
  1281. /**********************/
  1282. void DoOptions()
  1283. {
  1284.     short i,j;
  1285.     
  1286.     gametype = arg[GAMETYPE];
  1287.     gamelength = arg[GAMELENGTH];
  1288.     stripper = arg[STRIPPER];
  1289.     opponent = arg[OPPONENT];
  1290.     balls = arg[BALLCOUNT];
  1291.         
  1292.     switch(gametype)
  1293.     {
  1294.         case PLYR1: CopyPlayer(2,0); CopyPlayer(opponent+4,1); break;
  1295.         case PLYR2: CopyPlayer(2,0); CopyPlayer(3,1); break;
  1296.         case PRACTICE: CopyPlayer(2,0); CopyPlayer(2,1); break;
  1297.         case DEMO:
  1298.             i = Rand(4); do j = Rand(4); while (i==j);
  1299.             CopyPlayer(4+i,0); CopyPlayer(4+j,1); break;
  1300.     }
  1301.     if (gamelength==BEST3) matches=3;
  1302.     else if (gamelength==BEST5) matches=5;
  1303.         
  1304.     rgb2[_ltbaize] = RGBbaize[arg[BAIZE]*5];
  1305.     rgb2[_dkbaize] = RGBbaize[arg[BAIZE]*5+1];
  1306.     rgb2[_baize] = RGBbaize[arg[BAIZE]*5+2];
  1307.     rgb2[_ltbaize2] = RGBbaize[arg[BAIZE]*5+3];
  1308.     rgb2[_ltbaize3] = RGBbaize[arg[BAIZE]*5+4];
  1309.  
  1310.     rgb2[_red] = RGBball[arg[BALL1]];
  1311.     rgb2[_highred] = 0xfff;
  1312.     rgb2[_yellow] = RGBball[arg[BALL2]];
  1313.     rgb2[_highyel] = 0xfff;    
  1314.     
  1315.     FadeScreen(s,DOWN); SetRast(rp,_back);
  1316.     for (i=0; i<32; i++) rgb[i] = rgb2[i];
  1317.  
  1318.     if (gametype!=PRACTICE)
  1319.     {
  1320.         WriteMessage(player[0].nametag,80,80,NEW);
  1321.         WriteMessage(MSG_VS,0,80,FOLLOW);
  1322.         WriteMessage(player[1].nametag,0,80,FOLLOW);
  1323.         FadeScreen(s,UP); ClickDelay(150);
  1324.     }
  1325.     LoadIFF(&tableIFF,s,VIEW);
  1326.     BltBitMap(bm,182,107,&bufbm,200,0,71,79,0xc0,31,buffer);
  1327. }
  1328. /********************* Allocatation Routines ***********************/
  1329. short AudioOpenIt()
  1330. {
  1331.     short i;    
  1332.  
  1333.     bufwave = AllocMem(BUFWAVELEN,MEMF_CLEAR | MEMF_CHIP);
  1334.  
  1335.     for (i=0; i<4; i++)
  1336.     {
  1337.         if (!(audio[i] = (struct IOAudio *) GetDeviceBlock(AUDIO_LEN)))
  1338.             return(0);
  1339.     
  1340.         audio[i]->ioa_Data = &Channel_Map[i];
  1341.         audio[i]->ioa_Length = 1; /* sizeof(Channel_Map); */
  1342.         audio[i]->ioa_Request.io_Message.mn_Node.ln_Pri = PRECIDENCE;
  1343.         if (OpenDevice("audio.device",NULL,audio[i],NULL)) return(0);
  1344.         /* Cut out initial noise */
  1345.         Audio_PerVol(audio[i],124,0);
  1346.         Audio_Write(audio[i],bufwave,BUFWAVELEN);
  1347.     }
  1348.     for (i=0; i<SAMPLES; i++)
  1349.     {        
  1350.         while (!(fh = (struct FileHandle *)
  1351.             Open(audioinfo[i].filename,MODE_OLDFILE)));
  1352.         
  1353.         audioinfo[i].audio = audio[audioinfo[i].channel];
  1354.         audioinfo[i].wave =
  1355.             AllocMem(audioinfo[i].wavelen,MEMF_CLEAR | MEMF_CHIP);
  1356.         Seek((BPTR)fh,AM2,OFFSET_BEGINNING);
  1357.         MyRead(fh,audioinfo[i].wave,audioinfo[i].wavelen);
  1358.         Close((BPTR)fh);
  1359.     }
  1360.     return(1);
  1361. }
  1362. /************************/
  1363. void CloseIt()
  1364. {
  1365.     short i;
  1366.  
  1367.     prefs.KeyRptSpeed.tv_micro = oldkeyspeed;
  1368.     prefs.KeyRptDelay.tv_micro = oldkeydelay;
  1369.     SetPrefs(&prefs,sizeof(struct Preferences),TRUE);
  1370.  
  1371.     for (i=0; i<4; i++)
  1372.         FreeDeviceBlock(audio[i],(BYTE)CLOSE_DEVICE);    
  1373.  
  1374.     for (i=0; i<SAMPLES; i++) if (audioinfo[i].wave)
  1375.         FreeMem(audioinfo[i].wave,audioinfo[i].wavelen);
  1376.     if (bufwave) FreeMem(bufwave,BUFWAVELEN);
  1377.  
  1378.     for (i=0; i<5; i++)
  1379.         if (bufbm.Planes[i]) FreeRaster(bufbm.Planes[i],320,256);
  1380.  
  1381.     if (memblock) FreeMem(memblock,MEMSIZE);
  1382.     if (w) CloseWindow(w);
  1383.     if (w2) CloseWindow(w2);
  1384.     if (s) CloseScreen(s);
  1385.     if (s2) CloseScreen(s2);
  1386.     if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
  1387.     if (GfxBase) CloseLibrary((struct Library *)GfxBase);
  1388. }
  1389. /**********************/
  1390. UWORD Rand(max)
  1391. UWORD max;
  1392. {
  1393.     seed = seed*seed + 5*seed + VBeamPos();
  1394.     return (seed % max);
  1395. }
  1396. /**********************/
  1397. void CheckAngle(angle)
  1398. short *angle;
  1399. {
  1400.     if (*angle > 359) *angle-=360;
  1401.     else if (*angle < 0) *angle+=360;
  1402. }
  1403. /**********************/
  1404. short FindAngle(opp,adj,hyp)
  1405. WORD opp,adj,hyp;
  1406. {
  1407.     register short angle;
  1408.     
  1409.     if (opp > hyp) opp=hyp;
  1410.     else if (-opp > hyp) opp=-hyp;
  1411.     angle = quickarcsin[abs(opp * 5000 / hyp)];
  1412.     if (adj < 0 && opp >= 0) angle=180-angle;
  1413.     else if (adj < 0 && opp < 0) angle+=180;
  1414.     else if (adj >= 0 && opp < 0) angle=360-angle;
  1415.     return angle;
  1416. }
  1417. /**********************/
  1418. WORD QuickRoot(x)
  1419. long x;
  1420. {
  1421.     register USHORT y=2,dy;
  1422.     register ULONG ysq;
  1423.     
  1424.     while(y*y < x) y<<=1;
  1425.     dy=y>>1;
  1426.     
  1427.     while(1)
  1428.     {    
  1429.         ysq = y*y;
  1430.         if (ysq==x) return y;
  1431.         if (ysq < x) y+=dy;
  1432.         else y-=dy;
  1433.         if (!(dy>>=1))
  1434.         {
  1435.             if (y*y < x) y++; /* add 1? - hyp not < opp or adj! */ 
  1436.             return y;
  1437.         }
  1438.     }
  1439. }
  1440. /********************/
  1441. APTR GetDeviceBlock(size)
  1442. ULONG size;
  1443. {
  1444.     struct MsgPort *port;
  1445.     APTR request;
  1446.     
  1447.     if (!(port = (struct MsgPort *) CreatePort(0,0))) return(NULL);
  1448.     
  1449.     if (!(request = (APTR) CreateExtIO(port,size)))
  1450.     { DeletePort(port); return(NULL); }
  1451.     
  1452.     return(request);
  1453. }
  1454. /********************/
  1455. void FreeDeviceBlock(audio,close)
  1456. struct IOAudio *audio;
  1457. BYTE close;
  1458. {
  1459.     if (audio->ioa_Request.io_Message.mn_ReplyPort)
  1460.         DeletePort(audio->ioa_Request.io_Message.mn_ReplyPort);
  1461.     if (close && audio->ioa_Request.io_Device) CloseDevice(audio);
  1462.     DeleteExtIO(audio);
  1463. }
  1464. /********************/
  1465. void PlaySound(info,volume)
  1466. struct audioinfostruct *info;
  1467. short volume;
  1468. {
  1469.     if (CheckIO(info->audio))
  1470.     {
  1471.         info->volume = volume;
  1472.         if (info->flag==RESET)
  1473.         {
  1474.             Audio_PerVol(info->audio,124,0);
  1475.             Audio_Write(info->audio,info->wave,info->wavelen);
  1476.             while(!(CheckIO(info->audio)));
  1477.             Audio_PerVol(info->audio,info->period,info->volume);
  1478.             Audio_Write(info->audio,bufwave,BUFWAVELEN);
  1479.         }
  1480.         else /* flag == BUFFER */
  1481.         {
  1482.             Audio_PerVol(info->audio,info->period,info->volume);
  1483.             if (info->bufstate = 1 - info->bufstate)
  1484.                 Audio_Write(info->audio,info->wave,info->wavelen);
  1485.             else Audio_Write(info->audio,bufwave,BUFWAVELEN);
  1486.         }
  1487.     }
  1488. }
  1489. /********************/
  1490. void Audio_PerVol(audio,period,volume)
  1491. struct IOAudio *audio;
  1492. UWORD period,volume;
  1493. {
  1494.     audio->ioa_Request.io_Flags = ADIOF_SYNCCYCLE;
  1495.     audio->ioa_Period = period;
  1496.     audio->ioa_Volume = volume;
  1497.     audio->ioa_Request.io_Command = ADCMD_PERVOL;
  1498.     SendIO(audio);
  1499. }
  1500. /********************/
  1501. void Audio_Write(audio,waveform,wavelength)
  1502. struct IOAudio *audio;
  1503. UBYTE *waveform;
  1504. UWORD wavelength;
  1505. {
  1506.     audio->ioa_Data = waveform;
  1507.     audio->ioa_Request.io_Command    = CMD_WRITE;
  1508.     audio->ioa_Request.io_Flags = 0;
  1509.     audio->ioa_Length = wavelength;
  1510.     audio->ioa_Cycles = 1;
  1511.     SendIO(audio);
  1512. }
  1513.  
  1514. /************************/
  1515. void CopyBalls(fromball,toball)
  1516. struct ballstruct *fromball,*toball;
  1517. {
  1518.     short i;
  1519.     
  1520.     for (i=0; i<balls; i++)
  1521.     {
  1522.         toball[i].x = fromball[i].x;
  1523.         toball[i].y = fromball[i].y;
  1524.         toball[i].scrnx = fromball[i].scrnx;
  1525.         toball[i].scrny = fromball[i].scrny;
  1526.         toball[i].angle = fromball[i].angle;
  1527.         toball[i].speed = fromball[i].speed;
  1528.         toball[i].potted = fromball[i].potted;
  1529.         toball[i].justpotted = fromball[i].justpotted;
  1530.     }
  1531.